/***************************************************************
                             ibc.c V4.6
***************************************************************/
#include <stdio.h>
#include <malloc.h>
#include "clam.h"
#include <gtk/gtkwidget.h>

#include <sys/times.h>
#ifdef MAC_BUILD
#include "time.h"
#endif

#define Outlog {if (Pz.logFlag && Zlogfp!=NULL) {fprintf(Zlogfp,"%s",ZBuf); fflush(Zlogfp);} if (Pz.stdFlag) {printf("%s",ZBuf);}}

#define graphQuery messQuery

int ZincrFlag=0;
extern int get_seed_clone(), get_Zset();
extern int Greedy_make_Zset(), Zcreate_node(), 
            loadCz(), loadCzfast(), Zbuild_matrix();
extern int  comparedates(), Zbury_type();
extern void refreshlist(), updateproj();
extern int Zmove_ctg(), Do_BestOf();
extern void AutoCtgMsg(), settime(), move_selected();
extern void clearMsg(), OK_Zset(), Zproj_results();
extern void bury(), unbury();     /* fpp */
extern void cbmap_sort(), cleanCB(); /* cbmap.c */
extern void quitCB(), showClam(), showClam2();
extern void Zfree_cb_data_structures(), Zmark_possible_buried();
extern int ZibcCpM();
extern int ZnoCB, cnt_nodes, cnt_overlap;
extern GtkWidget *ctg_window;
extern void fix_cb_offsets();
extern void pr_end_timer(), Zcalc_zap(), CBlayout();

BOOL ZboolCpM();
int init_CpM();
void print_CpMcnts();

#define XAUTO -2
#define XAUTOUPDATE -3

#define XMARK -1
#define XCTG0 -2
#define Xreject 2

/****************************************************************
                       Def: Zincremental_build_zap
****************************************************************/
void Zincremental_build_zap()
{
int i, j=0, k, c;
CLONE *clpi, *clpk;
int  ctgcnt[4];
char tmp[1000], merge_msg[1000];
int  new_clones=0, cntTotalMerge=0, cntTotalAddNew=0, cntTotalAddOld=0, firstNewCtg,  first_ctg;
int  new_markers=0, cntNewCtg=0, avoid=0, ctgThisCtgAdd=0, cntctg0;
int  mark_single=0, last_contig=0;
int tmp1, tmp2;
BOOL found, mflag;
int  next_ctg;
char *ptr, lastbuild[100];
struct markertop *top;
double save_score;
int save_best, cntpos;
int saveshow;
struct mytime curdate;
struct tm *curr_time;
time_t ltime;
clock_t start=0,end=0, start2=0, end2=0;
struct tms tmsstart,tmssend, tmsstart2, tmssend2;
float avg_high_score=0.0;
int   cnt_calc=0, cnt_Q_ctg=0;
long cnt_Qs=0;

  if (!ZibcCpM()) return;

  if(ctg_window!=NULL) gtk_widget_destroy(ctg_window);

  if (graphActivate(g99)) quitCB();
  else cleanCB();
  fix_cb_offsets(); /* cas 20feb04 - use routine in c2am.c so Qs aren't set to -1 */

  start=times(&tmsstart);

     /* get rid of previous IBC results */
  PRTMESS=0;
  for (tmp1=i=0; i<= max_contig ; i++) {
     if (contigs[i].count == 0) continue;
     k=j=0;
 
     while (contigs[i].trace_msg[j]!='\0')
     {
       if (contigs[i].trace_msg[j]=='I' && contigs[i].trace_msg[j+1]=='B'
                                     && contigs[i].trace_msg[j+2]=='C') {
             while (contigs[i].trace_msg[j]!=' ' &&
                    contigs[i].trace_msg[j]!='\0') j++;
       }
       if (contigs[i].trace_msg[j]!='\0')
             merge_msg[k++] = contigs[i].trace_msg[j++];
     }
     merge_msg[k]='\0';
     strncpy(contigs[i].trace_msg, merge_msg, CTGMSG_SZ-1);

     contigs[i].projmsg[0] = '\0';
     contigs[i].ctgIBC = ' ';
     if (NoBuild(i)) avoid++;
     if (NoCBmap(i)) tmp1++;
     j = i;
  }
  PRTMESS=0;
  next_ctg=firstNewCtg=j+1;
  sprintf(ZBuf,"\nIncremental Build Contigs:\n"); Outlog;
  if (!init_CpM(1)) {Outlog; return;}

/********** FIND clones to process and set fields **********/
  for (tmp2 = i= 0; i < arrayMax(acedata); i++)
  {
     clpi = arrp(acedata, i, CLONE);
     clpi->oldctg = clpi->ctg;
     clpi->ibc = 0;

     if (Cp.useFlag) {
       found=0;
       for (top = clpi->marker; top!=NULL; top = top->nextmarker)
          if (top->new==1) {
              top->new=2;
              found=TRUE;
          }
          else top->new=0;

       if (found) {
           if (clpi->ctg==0) mark_single++;
           new_markers++;
           clpi->ibc = XMARK;
           last_contig = MaX(last_contig, clpi->ctg);
       }
     }

     if (clpi->ctg!=0) continue;
     if (clpi->clone[0] == '!') continue;
     if (clpi->match[0]!=' ') unbury(i);

     if (time(&ltime) != -1) {
       curr_time = localtime(&ltime);

       if (curr_time->tm_year > 99) {
    /* subtract 1 century from the current year so that if we are past 2000
        searchdate will be set to the correct century.*/

         curdate.year = curr_time->tm_year - 100;
         curdate.month = curr_time->tm_mon+1;
         curdate.day = curr_time->tm_mday;
         curdate.hour = curr_time->tm_hour;
         curdate.minute = curr_time->tm_min;
      /* keep looping until we pass today-100 years */
         while (comparedates(&Bd.date, &curdate)!=-1) {
           Bd.date.year = Bd.date.year + 100;
         }
       }
     }
     if (comparedates(&Bd.date, &(clpi->creation_date))> 0) {
         new_clones++; 
         clpi->ibc = XCTG0;
     }
     else tmp2++;
  }

  if (new_clones==0 && new_markers==0) {
      PRTMESS=1;
      printf("No new clones since Last build date %d/%d/%d\n",
               Bd.date.day, Bd.date.month, Bd.date.year);
      return;
  }

  if (ZnoCB) sprintf(ZBuf,"Do not run CB algorithm on existing contigs.\n");
  else sprintf(ZBuf,"Status NoCB %d Avoid %d.\n", tmp1, avoid);
  Outlog;
  if (new_clones>0) {
      sprintf(ZBuf,"Processing %d new singletons. Old singletons %d.\n", new_clones,tmp2);
      Outlog;
  }
  if (new_markers>0) {
      sprintf(ZBuf,"New %d clone markers to process. Single markers %d.\n",
              new_markers, mark_single);
      Outlog;
  }
  sprintf(lastbuild, "Last %d/%d/%d (New %d,%d)", 
    Bd.date.day, Bd.date.month, Bd.date.year, new_clones, new_markers);
  settime(&Bd.date);
  new_clones=0;
  PRTMESS=0;
  ZincrFlag=1;

/************* MAIN LOOP1 thru all contigs for new clones ********/
/* Note that the first contig is ctg0 to get all new clones */
/* after that it is getting clones with markers */
/* last_contig is the last one with marker changes */

  for (c= 0; c<=last_contig; c++) {
     if (contigs[c].count==0) continue;
     if (NoBuild(c)) continue;

     if (!Zbatch_flag && graphInterruptCalled()) {
         printf("F4 pre-mature termination of Incremental Build\n");
         goto FINISH;
     } 

     for (i= contigs[c].start; i != -1;) 
     {
        clpi = arrp(acedata, i, CLONE);
        if (clpi->ibc >= 0 || !loadCz(&C1z, i)) {
           i = clpi->next;
           continue;
        }

        if (++new_clones % 100 == 0) 
          printf("Processing clone %d  Merge %d CtgNew %d  AddNew %d AddOld %d\n", 
                      new_clones, cntTotalMerge, cntNewCtg,  
                      cntTotalAddNew, cntTotalAddOld);

        mflag = FALSE; ctgThisCtgAdd=cntctg0=0; merge_msg[0]='\0';

        if (clpi->ctg==0) first_ctg = 0;
        else {
          j = first_ctg = clpi->ctg;
          if (contigs[j].projmsg[0]!='\0') {
              sscanf(contigs[j].projmsg,"%d",&ctgThisCtgAdd);
              if ((ptr = strstr(contigs[j].projmsg,"Ctg"))!=NULL)
                   strcpy(merge_msg, ptr);
          }
        }
 
   /***  LOOP thru all contigs and merge any with a match clone */

        for (j= 1; j<=max_contig; j++) {
            if (j==clpi->ctg) continue;
            if (contigs[j].count==0) continue;
            if (NoBuild(j)) continue;

          /** Loop thur clones of contig looking for a match **/
            for (found=FALSE, k= contigs[j].start; k != -1 && !found; 
                                                    k = clpk->next) {
               clpk = arrp(acedata, k, CLONE);
               loadCzfast(&C2z, k);
               Zsulston(&C1z,&C2z,&Sz);
               if (ZboolCpM()) found = TRUE;
            }
            if (!found) continue;
 
            if (first_ctg==0) { /* add single to first contig hit */
                first_ctg=j;
                if (contigs[first_ctg].projmsg[0]!='\0') {
                    sscanf(contigs[first_ctg].projmsg,"%d",&ctgThisCtgAdd);
                    if ((ptr = strstr(contigs[j].projmsg,"Ctg"))!=NULL) 
                       strcpy(merge_msg, ptr);
                }
                     /* move new clone to left of contig */
                ctgThisCtgAdd++; cntTotalAddNew++; cntctg0++;
                clpi->selected = TRUE;
                clpi->x = 0;
                clpi->y = clpi->fp->b2;
                move_selected(0, first_ctg, 0); 
                continue;          
            }
                        /*** merge - source clone is in contig ****/
            mflag=TRUE;
                       /** update message and counts **/
            if (contigs[j].projmsg[0]!='\0') {
                if ((ptr = strstr(contigs[j].projmsg,"Ctg"))!=NULL) strcat(merge_msg, ptr);
                sscanf(contigs[j].projmsg,"%d",&tmp1);
                ctgThisCtgAdd += tmp1; 
            }
            if (j<firstNewCtg) { /* else just created earlier */
               if (merge_msg[0]=='\0') sprintf(merge_msg,"Ctg%d", j);
               else {
                  sprintf(tmp," Ctg%d", j);
                  strcat(merge_msg,tmp);
               }
               sprintf(tmp,"IBC%d", j);
               AutoCtgMsg(first_ctg, tmp);
               cntTotalMerge++;
            } 
            else {
               cntNewCtg--;
            }  
                       /** preform merge **/
            for (k= contigs[j].start; k != -1; k = clpk->next) {
                clpk = arrp(acedata, k, CLONE);
                clpk->selected = TRUE;
            }
            move_selected(j, first_ctg, contigs[first_ctg].right+10); 
         }
   
   /*** LOOP thru all OLD singles. Not unprocessed new as they need to be check 
     against everything. But if processed and had no joins, can now be added
     to this one. Another 'new' one will later be checked against this one. */

         for (k= contigs[0].start; k != -1; k = clpk->next) {
            clpk = arrp(acedata, k, CLONE);
            if (clpk->ibc < 0) continue;
            if (k==i) continue;
            if (clpk->fp==NULL) continue;

            loadCzfast(&C2z, k);
            Zsulston(&C1z,&C2z,&Sz);
            if (!ZboolCpM()) continue;
    
            ctgThisCtgAdd++; cntctg0++;
            if (clpk->ibc==Xreject) cntTotalAddNew++;
            else cntTotalAddOld++;
            clpk->ibc=0;
           
            clpk->selected=TRUE;
            clpk->x = clpi->x;
            clpk->y = clpi->x+clpk->fp->b2;
                /* if going into a old ctg, this is only hit so bury it,
                   this will get undone if the ctg is rebuild */
            if (first_ctg!=0 && first_ctg < firstNewCtg) { 
                clpk->parent = i;
                strcpy(clpk->match,clpi->clone);
                clpk->mattype = Zbury_type(k,i);
                if(!(clpk->mattype & PSEUDO)) clpi->mattype = PARENT;
                else if (clpi->mattype == 0) clpi->mattype = PSPARENT;
                clpi->selected=TRUE;
            }
         }
  
       /********* Comparisons are done ******/

         if (cntctg0==0 && !mflag) {
             clpi->ibc = Xreject;
             i = clpi->next;
             continue;
         } 
         if (clpi->ibc==XCTG0) clpi->ibc = 0;
         else clpi->ibc = 1;
 
         if (first_ctg==0) {       /* new contig */
            ctgThisCtgAdd++; cntTotalAddNew++;
            clpi->selected = TRUE;
            clpi->x = 0;
            clpi->y = clpi->fp->b2;
         
            cntNewCtg++;
            first_ctg = next_ctg; 
            next_ctg++;
            sprintf(merge_msg,"%2d New", ctgThisCtgAdd);
         }
         else if (first_ctg >= firstNewCtg) {
            sprintf(merge_msg,"%2d New", ctgThisCtgAdd);
         }
         else   {
            strcpy(tmp, merge_msg);
            if (merge_msg[0]=='\0') sprintf(merge_msg,"%2d", ctgThisCtgAdd);
            else sprintf(merge_msg,"%2d %s", ctgThisCtgAdd, tmp);
         }
         move_selected(0, first_ctg, 0);

         contigs[first_ctg].ctgQs = XAUTOUPDATE;
         strncpy(contigs[first_ctg].projmsg,merge_msg, MSGSIZE-1);

         i = contigs[c].start;

     } /* end loop for clones for contig **/

  } /* end MAIN LOOP1  thru contigs **/

  ZincrFlag=0;
  printf("Merge %d NewCtg %d  AddNew %d AddOld %d\n", 
           cntTotalMerge, cntNewCtg,   cntTotalAddNew, cntTotalAddOld);
  if (cntTotalMerge==0 && cntTotalAddNew==0) {
        PRTMESS=1;
        return;
  }
  next_ctg = Zmove_ctg(firstNewCtg, next_ctg, 0);
  
  end=times(&tmssend);
  start2=times(&tmsstart2);

/******* MAIN LOOP2 - position clones ******/
  ctgcnt[0]=ctgcnt[1]=ctgcnt[2]=ctgcnt[3]=0;
  saveshow = showburied;
  showburied = 0;
  printf("\n");
  for (j= 1; j<=max_contig; j++) {
     if (contigs[j].count == 0) continue;
     if (contigs[j].ctgQs != XAUTOUPDATE) {
        if (contigs[j].ctgQs < -1) contigs[j].ctgQs = -1;
        continue;
     }
     if (!Zbatch_flag && graphInterruptCalled()) {
          printf("F4 pre-mature termination of Incremental Build\n");
          goto FINISH;
     } 

     contigs[j].ctgIBC = '+';
     update++;
     PRTMESS=0;        /* get set to 1 in OK_Zset */

     if (NoCBmap(j) || (ZnoCB && j<firstNewCtg)) goto AutoAddOnly;

          /**** Run CBmap ****/
     qstuff=1;
     currentctg = contigs[j].ctg;
     find_Clone(j);
     LastCB=IBC;    

     Zcalc_zap();
     avg_high_score += Zset[0].score;
     cnt_Qs += Zset[0].n_Qs;
     if (Zset[0].n_Qs>0) cnt_Q_ctg++;
     cnt_calc++;
     if (contigs[currentctg].count > 50) ctgcnt[0]++;
     else if (contigs[currentctg].count > 25) ctgcnt[1]++;
     else if (contigs[currentctg].count > 3) ctgcnt[2]++;
     else ctgcnt[3]++;

     CBlayout();
     currentctg = 0;
     Zfree_cb_data_structures();
     continue;

AutoAddOnly: ;        /*** only position new clones ***/
     cntpos=0; save_score=15.0; save_best=-1;
     for (k= contigs[j].start; k != -1; k = clpk->next) {
         clpk = arrp(acedata, k, CLONE);
         if (clpk->oldctg!=0) continue;
         loadCzfast(&C1z, k);

         save_score=15.0; save_best=-1;
         for (i= contigs[j].start; i != -1; i = clpi->next) {
               clpi = arrp(acedata, i, CLONE);
               if (clpi->oldctg==0) continue;
               loadCzfast(&C2z, i);
               Zsulston(&C1z,&C2z,&Sz);
               if (Sz.prob < save_score) {
                   save_score=Sz.prob;
                   save_best=i;
               }
         }
         if (save_best!=-1) {
            clpk->selected=TRUE;
            clpi = arrp(acedata, save_best, CLONE);
            clpk->x = clpi->x;
            clpk->y = clpi->x + clpk->fp->b2;
            cntpos++;
         }
     }
     if (cntpos>0) move_selected(j, j, 0);
     contigs[j].ctgQs = -1;
     sprintf(merge_msg, "%s NoCB",  contigs[j].projmsg);
     strncpy(contigs[j].projmsg, merge_msg, MSGSIZE-1);
   }
   showburied = saveshow;
   end2=times(&tmssend2);
  /********** Write stats to output ***********/
FINISH: ;
   sprintf(ZBuf, "Update %d Merge %d NewCtg %d Add %d",
       update, cntTotalMerge, cntNewCtg, cntTotalAddNew+cntTotalAddOld);
   showClam2();

   sprintf(ZBuf,"\nComplete IBC\n"); Outlog;
   print_CpMcnts(); Outlog;
   sprintf(ZBuf, "Update %d Merge %d NewCtg %d NewAdd %d OldAdd %d  Modified %d/%d/%d %d:%d\n",
          update, cntTotalMerge, cntNewCtg,  cntTotalAddNew, cntTotalAddOld,
          Bd.date.day, Bd.date.month, Bd.date.year, Bd.date.hour, Bd.date.minute-1);
   Outlog;
   if (cnt_calc>0) {
      sprintf(ZBuf, "IBC %d: Qs %ld(%d) AvgScore %3.2f ",
            cnt_calc, cnt_Qs, cnt_Q_ctg, avg_high_score/(float) cnt_calc); 
      Outlog;
      sprintf(ZBuf," %d (>50), %d (50:26), %d (25:4), %d (<4)\n",
              ctgcnt[0], ctgcnt[1], ctgcnt[2], ctgcnt[3]); Outlog;
      if (cntNewCtg>0) 
         sprintf(ZBuf,"First new contig %d\n",firstNewCtg);
   }

   pr_end_timer("Calculate merges:", end-start,&tmsstart,&tmssend);
   pr_end_timer("Perform   merges:", end2-start2,&tmsstart2,&tmssend2);

   PRTMESS=1;
   qstuff = 0;
   ClamCtgDisplay2();
   Zproj_results(1);
}
/************************************************************
                DEF: Z_undoInc()
*************************************************************/
void Z_undoInc()
{
int  xctg=0, tctg, cnt, cntall;
CLONE *clp, *clpp;
struct contig *p;

if (!messQuery("Are you sure you want to Undo Additions?")) return;

PRTMESS=0;
   cntall=0;
   while (xctg != -1)
   {
      xctg = -1; cnt=0;
      for (p = root; p != NULL; p = p->new)
      {
         clp = arrp(acedata, p->next, CLONE);
         clp->selected=FALSE;
         tctg = clp->oldctg;
         if (tctg == currentctg) continue;

         if (xctg == -1)  xctg = tctg;
         if (xctg != tctg) continue;
         cnt++;
         clp->selected=TRUE;
         clp->oldctg = currentctg; /* loop if this is not done */
         if (clp->parent!=-1) {
             clpp = arrp(acedata, clp->parent, CLONE);
             tctg = clpp->oldctg;
             if (xctg!=tctg) unbury(p->next);
         } 
      }
      if (xctg!= -1) {
         if (contigs[xctg].count!=0 && xctg!=0) {
            printf("Contig %d exists, Moving clones to contig %d. ",
                    xctg, max_contig+1);
            xctg = max_contig+1;
         }
         printf("Move %d clones to Ctg%d.\n",cnt, xctg);
         move_selected(currentctg, xctg, 0);
         cntall++;
      }
   }
   if (cntall> 0) {
      AutoCtgMsg(currentctg, "Undo");
      newctg=TRUE;
      ctgdisplay(currentctg);
      refreshlist();
      updateproj();
   }
PRTMESS=1;
}
